home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Source Code
/
Pascal
/
Applications
/
DropBin 1.5
/
BinHex.p
next >
Wrap
Text File
|
1997-04-16
|
11KB
|
445 lines
Unit Binhex;
{$NR+}
Interface
Uses
Toolbox, DropBinUtils, BinProgress;
Const
BinHexOpen = 5807;
BufferSize = 4096;
MemErr = 6417;
BinHexRead = 5811;
BinHexTable = '!"#$%&''()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr';
BinHexHeader = '(This file must be converted with BinHex 4.0)';
Var
DontTranslate: Boolean; { don't use translation tables }
CommandPeriod: Boolean; { has cmd-. been pressed lately? }
State86: SignedByte;
SavedBits: SignedByte;
LineLength: SignedByte;
Function BinHexFile(vRef: integer; dirId: longint; name: str255): integer;
Implementation
{************************************************************************
* EncodeDataChar - encode an 8-bit data char into a six-bit buffer
* returns the number of valid encoded characters generated
************************************************************************}
Function EncodeDataChar(c: SignedByte; toSpot: Ptr): integer;
Var
spotWas: Ptr;
Procedure Addnewline;
begin
linelength := 0;
toSpot^ := kReturnKey;
OffsetPtr(toSpot,1);
end;
Var
i: integer;
begin
spotWas := toSpot;
case State86 of
0: begin
i := BAnd(BSR(c,2),$3F);
toSpot^ := SignedByte(BinHexTable[i+1]);
OffsetPtr(toSpot, 1);
SavedBits := BSL(BAnd(c,$03),4);
inc(lineLength);
if lineLength = 64 then
Addnewline;
end;
1: begin
i := BOr(SavedBits,BAnd(BSR(c,4),$0F));
toSpot^ := SignedByte(BinHexTable[i+1]);
OffsetPtr(toSpot, 1);
SavedBits := BSL(BAnd(c,$0f),2);
inc(lineLength);
if lineLength = 64 then
Addnewline;
end;
2: begin
i := BOr(SavedBits,BAnd(BSR(c,6),$03));
toSpot^ := SignedByte(BinHexTable[i+1]);
OffsetPtr(toSpot, 1);
inc(lineLength);
if lineLength = 64 then
Addnewline;
i := BAnd(c,$3f);
toSpot^ := SignedByte(BinHexTable[i+1]);
OffsetPtr(toSpot, 1);
inc(lineLength);
if lineLength = 64 then
Addnewline;
State86 := -1;
end;
end; { of CASE }
inc(State86);
EncodeDataChar := ORD4(toSpot) - ORD4(spotWas);
end;
Procedure CalcCRC(c: unsignedWord);
Const
ByteMask = $0FF;
WordMask = $0FFFF;
WordBit = $10000;
CrcConstant = $01021;
Var
i: integer;
begin
c := BAnd(c, ByteMask);
for i := 1 to 8 do
begin
c := BSL(c,1);
mainCRC := BSL(mainCRC,1);
if BAnd(mainCRC,WordBit) <> 0 then
mainCRC := BXOr(BAnd(mainCRC,WordMask), CrcConstant);
mainCRC := BXOr(mainCRC,BSR(c,8));
c := BAnd(c, ByteMask);
end;
end;
Procedure Code(dc: SignedByte; var codedSpot: integer; codedBuffer: Ptr);
Procedure LCode(dc: SignedByte);
begin
codedSpot := codedSpot +
EncodeDataChar(dc,Ptr(ORD4(codedBuffer) + codedSpot));
end;
begin
LCode(dc);
if dc = -112 then
LCode(0);
CalcCRC(dc);
end;
Procedure CodeShort(ds: integer; var codedSpot: integer; codedBuffer: Ptr);
Var
cp: Ptr;
begin
cp := @ds;
Code(cp^, codedSpot, codedBuffer);
Code(AddPtrLong(cp,1)^, codedSpot, codedBuffer);
end;
Procedure CodeShortInt(ds: integer; var codedSpot: integer; codedBuffer: Ptr);
Var
cp: Ptr;
begin
cp := @ds;
Code(AddPtrLong(cp,1)^, codedSpot, codedBuffer);
Code(cp^, codedSpot, codedBuffer);
end;
Procedure CodeLong(dl: longint; var codedSpot: integer; codedBuffer: Ptr);
Var
copy: longint;
cp: Ptr;
begin
copy := dl;
cp := @dl;
Code(cp^, codedSpot, codedBuffer);
Code(AddPtrLong(cp,1)^, codedSpot, codedBuffer);
Code(AddPtrLong(cp,2)^, codedSpot, codedBuffer);
Code(AddPtrLong(cp,3)^, codedSpot, codedBuffer);
end;
Function WriteBuffer(buffptr: univ Ptr; buffsize: longint): integer;
begin
WriteBuffer := FSWrite(gRefNum, buffsize, buffptr);
end;
Procedure WriteZero(pointer: Ptr; size: longint);
begin
while size > 0 do
begin
pointer^ := 0;
OffsetPtr(pointer,1);
dec(size);
end;
end;
Function DeleteFile(name: str255; vRefN: integer; dirId: longint): integer;
Var
pb: HParamBlockRec;
begin
if FSClose(gRefNum) = 0 then;
pb.ioNamePtr := @name;
pb.ioVRefNum := vRefN;
pb.ioMisc := nil;
HFileParamPtr(@pb)^.ioDirID := dirID;
DeleteFile := PBHDeleteSync(@pb);
end;
Function FSHOpen(name: str255; vRefN: integer; dirId: longint;
var refN: integer; perm: integer): integer;
Var
pb: HParamBlockRec{HIOParam};
err: integer;
begin
pb.ioNamePtr := @name;
pb.ioVRefNum := vRefN;
pb.ioPermssn := perm;
pb.ioMisc := nil;
HFileParamPtr(@pb)^.ioDirID := dirID;
err := PBHOpenSync(@pb);
if err = noErr then
refN := pb.ioRefNum;
FSHOpen := err;
end;
Function RFHOpen(name: Str255; vRefN: integer; dirId: longint;
var refN: integer; perm: integer): integer;
Var
pb: HParamBlockRec;
err: integer;
begin
pb.ioCompletion := nil;
pb.ioNamePtr := @name;
pb.ioVRefNum := vRefN;
pb.ioVersNum := 0;
pb.ioPermssn := perm;
pb.ioMisc := nil;
HFileParamPtr(@pb)^.ioDirID := dirID;
err := PBHOpenRFSync(@pb);
if err = noErr then
refN := pb.ioRefNum;
RFHOpen := err;
end;
Function HGetFileInfo(vRef: integer; dirId: longint; name: str255; var hfi: HFileParam): integer;
Var
oe: integer;
begin
WriteZero(@hfi,sizeof(hfi));
hfi.ioNamePtr := @name;
hfi.ioVRefNum := vRef;
hfi.ioDirID := dirID;
oe := PBHGetFInfoSync(@hfi);
HGetFileInfo := oe;
end;
Function AddCRC(var idx: integer; codedBuffer: Ptr): OSErr;
Var
tempCrc: integer;
begin
CalcCRC(0);
CalcCRC(0);
tempCrc := BAnd(mainCRC, $FFFF);
CodeShort(tempCrc, idx, codedBuffer);
mainCRC := 0;
AddCRC := WriteBuffer(codedBuffer, idx);
end;
{************************************************************************
* BinHexFork - send one fork of a file as BinHex data
************************************************************************}
Function BinHexFork(refN: integer; dataBuffer: Ptr; dataSize: integer;
codedBuffer: Ptr; name: Str255): integer;
Var
dataEnd: longint;
bindex: integer;
err: OSErr;
spot: Ptr;
errWas: OSErr;
begin
bindex := 0;
repeat
dataEnd := dataSize;
err := FSRead(refN, dataEnd, dataBuffer);
if (err = noErr) or (err = eofErr) then
begin
errWas := err;
spot := dataBuffer;
while ORD4(spot) < ORD4(dataBuffer) + dataEnd do
begin
Code(spot^, bindex, codedBuffer);
OffsetPtr(spot, 1);
end;
err := WriteBuffer(codedBuffer, bindex);
bindex := 0;
if err = noErr then
err := errWas;
if UpdateProgress(dataEnd) <> 0 then
begin
DisplayMsg('Binhex operation cancelled on file "'+gFilename+'".');
BinHexFork := -1;
exit(BinHexFork);
end;
end;
if (err <> noErr) and (err <> eofErr) and (not CommandPeriod) then
AlertUser(name,err);
until err <> noErr;
if err = eofErr then
err := addCRC(bindex, codedBuffer);
if err = eofErr then
BinHexFork := noErr
else
BinHexFork := err;
end; { of BinHexFork }
{************************************************************************
* BinHexFile - convert a file to BinHex data
************************************************************************}
Function BinHexFile(vRef: integer; dirId: longint; name: str255): integer;
Var
refN: integer;
dataBuffer: Ptr;
codedBuffer: Ptr;
dataSize,
codedSize: longint;
i,codedSpot: integer;
err: OSErr;
hfp: HFileParam;
scratch: Str255;
Procedure ExitBinHex(e: integer);
begin
if refN <> 0 then
if FSClose(refN) = 0 then;
if dataBuffer <> NIL then
DisposePtr(Ptr(dataBuffer));
if codedBuffer <> NIL then
DisposePtr(Ptr(codedBuffer));
gProcessing := false;
InvalRect(dbWindow^.portRect);
DontTranslate := False;
if e <> noErr then
begin
e := DeleteFile(gOutputName, vRef, dirId);
if e <> noErr then
AlertUser('Error deleting file ' + gOutputName, e);
EndProgress;
ResetWindow(dbWindow);
end
else
EndProgress;
BinHexFile := e;
exit(BinHexFile);
end; { of ExitBinHex }
Procedure FailError(msg: str255; e: integer);
begin
AlertUser(msg, e);
ExitBinHex(e);
end; { of FailError }
begin
if gState then
begin
SetupProgress;
gState := false;
end;
gProcessing := true;
gFilename := name;
refN := 0;
dataBuffer := NIL;
codedBuffer := NIL;
err := HGetFileInfo(vRef,dirId,name,hfp);
if err <> noErr then
FailError('Error reading file header for ' + name, err); { file error }
{ allocate the buffers }
codedSize := 4096;
dataSize := codedSize div 3;
dataBuffer := NewPtrClear(datasize);
codedBuffer := NewPtrClear(codedsize);
if (dataBuffer = NIL) or (codedBuffer = NIL) then
FailError('Not enough memory', -108); { Memory error }
StartProgress(hfp.ioFlLgLen+hfp.ioFlRLgLen);
{ set the header }
scratch := chr(13) + BinHexHeader + chr(13) + chr(13) + ':';
err := WriteBuffer(@scratch[1], integer(scratch[0]));
if err <> noErr then
FailError('Error writing header', err); { Header error }
{ set the file information }
DontTranslate := True;
LineLength := 1;
State86 := 0;
mainCRC := 0;
codedSpot := 0;
for i := 0 to length(name) do
Code(byte(name[i]), codedSpot, codedBuffer);
Code(0, codedSpot, codedBuffer);
CodeLong(longint(hfp.ioFlFndrInfo.fdType), codedSpot, codedBuffer);
CodeLong(longint(hfp.ioFlFndrInfo.fdCreator), codedSpot, codedBuffer);
CodeShort(integer(hfp.ioFlFndrInfo.fdFlags), codedSpot, codedBuffer);
CodeLong(longint(hfp.ioFlLgLen), codedSpot, codedBuffer);
CodeLong(longint(hfp.ioFlRLgLen), codedSpot, codedBuffer);
err := addCRC(codedSpot, codedBuffer);
if err <> noErr then
FailError('Error calculating CRC for header', err);
{ data fork }
codedSpot := 0;
if vRef = 0 then
FailError('Invalid value for volume reference',-1);
err := FSHOpen(name,vRef,dirId,refN,fsRdPerm);
if err <> noErr then
FailError('Error opening data fork', err);
err := BinHexFork(refN, dataBuffer, dataSize, codedBuffer, name);
if err = -1 then
ExitBinHex(err)
else if err <> noErr then
FailError('Error encoding data fork',err);
{ resource fork }
codedSpot := 0;
if refN <> 0 then
FSClose(refN);
refN := 0;
err := RFHOpen(name,vRef,dirId,refN,fsRdPerm);
if err <> noErr then
FailError('Error opening resource fork', err);
err := BinHexFork(refN, dataBuffer, dataSize, codedBuffer, name);
if err = -1 then
ExitBinHex(err)
else if err <> noErr then
FailError('Error encoding resource fork', err);
{ leftovers }
if State86 <> 0 then
Code(0, codedSpot, codedBuffer);
PtrUpdate(codedBuffer,codedSpot,':');
inc(codedSpot);
PtrUpdate(codedBuffer,codedSpot,chr(13));
inc(codedSpot);
err := WriteBuffer(codedBuffer,codedSpot);
if err <> noErr then
FailError('Error completing binhex encoding', err);
ExitBinHex(noErr);
end;
End.